/*
    This file is part of Lynsync

    Lynsync is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Lynsync is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Lynsync; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 * 
 * History
 *   31,May 2007  V0.5   Start with Audolo file Copyright 2006  M.Janzen (Xaltos)
 * 
 * 
 * todo INI-File erstellen / Compare run for an Upload
 *            FAQ updaten
 */


using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

using System.Diagnostics;

using System.Security.Cryptography;
using Microsoft.Win32;

namespace Lynsync
{
	public partial class MainWindow : Form
	{
		const string GROUPS_INI_File = "Lynsync.List_of_groups.ini";
		string INI_File = "Lynsync.List_of_Server.ini";
		const string Download_File_List = "Lynsync.ini";
		const string Download_File_List_newFile = "Lynsync.gen.ini";

		const string VersionText = "Version 0.61";
		//  ^^^^^^^^^^^    Change the version also inside of properties
		
		bool ThreadRuningFlag = false;              // Is true during a Background thread
		string GameExePath = "";
		string GameExe = "";
		string LocalFilePath = "";
		ArrayList WorldLines = new ArrayList();
		
		public enum KeyIndex
		{
			Name = 0,
			Type,
			HomePage,
			RemoteINI,
			Folder,
			Server,
			Password,
			App,
			Options,
			Notes
		};
		
		WorldStorage mainWorldStorage;
		
		//---------------------------------------------------------------------------------------------
		public void SetPaths(bool isNwn2, bool isMydocs)
		{
			if (isNwn2)
			{
				RegistryKey NWN2key=Registry.LocalMachine.OpenSubKey("Software\\Obsidian\\NWN 2\\Neverwinter");
				string NWN2Path = "**** NWN2 not installed ****";
				if (NWN2key != null) NWN2Path = (string)NWN2key.GetValue("Location");
				GameExePath = NWN2Path;
				GameExe = GameExePath + "\\nwn2main.exe";
				if (isMydocs)
				{
					string Mydocs = Environment.GetFolderPath(Environment.SpecialFolder.Personal).ToString();
					string MydocsNWN2 = Mydocs + "\\Neverwinter Nights 2";
					LocalFilePath = MydocsNWN2;
				}
				else
				{
					LocalFilePath = NWN2Path;
				}				
			}
			else
			{
				RegistryKey NWN1key=Registry.LocalMachine.OpenSubKey("Software\\Bioware\\NWN\\Neverwinter");
				string NWN1Path = "**** NWN not installed ****";
				if (NWN1key != null) NWN1Path = (string)NWN1key.GetValue("Location");
				
				GameExePath = NWN1Path;
				GameExe = GameExePath + "\\nwmain.exe";
				LocalFilePath = NWN1Path;
			}
		}
		
		//---------------------------------------------------------------------------------------------
		// worldFolder, iso list
		public void UninstallWorldStorage(string worldFolder, string[] isoFolders)
		{
			AddTextToStatusBox("== Uninstall " + worldFolder + " =================\r\n");				
			DirectoryInfo dirModules = new DirectoryInfo(LocalFilePath + "\\modules\\"+ worldFolder);
			if (dirModules.Exists)
			{
				dirModules.Delete(true);
				AddTextToStatusBox("    Removed " + dirModules.FullName + "\r\n");				
			}
			DirectoryInfo dirCampaigns = new DirectoryInfo(LocalFilePath + "\\Campaigns\\"+ worldFolder);
			if (dirCampaigns.Exists)
			{
				dirCampaigns.Delete(true);
				AddTextToStatusBox("    Removed " + dirCampaigns.FullName + "\r\n");				
			}
			
			//foreach iso delete world
			deleteWorldFolder(LocalFilePath + "\\" + "hak", worldFolder);
			deleteWorldFolder(LocalFilePath + "\\" + "override", worldFolder);
			deleteWorldFolder(LocalFilePath + "\\" + "portraits", worldFolder);
			deleteWorldFolder(LocalFilePath + "\\" + "tlk", worldFolder);
			deleteWorldFolder(LocalFilePath + "\\" + "ui\\custom", worldFolder);
			deleteWorldFolder(LocalFilePath + "\\" + "ui\\default", worldFolder);
			listView1.Items.Clear();		
		}
		//---------------------------------------------------------------------------------------------
		bool CheckThread()
		{
			if (ThreadRuningFlag == false)
				return false;

			MessageBox.Show("There is a Process in the background active! \nPlease wait a bit ant try this later again.", "Lynsync", MessageBoxButtons.OK, MessageBoxIcon.Stop);
			return true;
		}
		
		//---------------------------------------------------------------------------------------------
		public string GetWorldKey()
		{
			string currentLine = (string)WorldLines[comboBoxWorld.SelectedIndex];
			return currentLine;
		}
		//---------------------------------------------------------------------------------------------
		public void NextWorldKey()
		{
			int index = comboBoxWorld.SelectedIndex + 1;
			if (index >= WorldLines.Count) index = 0;
			comboBoxWorld.SelectedIndex = index;
		}
		//---------------------------------------------------------------------------------------------
		public void PreviousWorldKey()
		{
			int index = comboBoxWorld.SelectedIndex - 1;
			if (index < 0) index = WorldLines.Count - 1;
			comboBoxWorld.SelectedIndex = index;
		}
		
		//---------------------------------------------------------------------------------------------
		delegate void AddTextToStatusBoxCallback(string Text);
		//---------------------------------------------------------------------------------------------
		// Texts ins Protokol schreiben
		public void AddTextToStatusBox(string Text)
		{
			if (this.StatusBox.InvokeRequired)
			{
				AddTextToStatusBoxCallback d = new AddTextToStatusBoxCallback(AddTextToStatusBox);
				this.Invoke(d, new object[] { Text });
			}
			else
			{

				int len = StatusBox.Text.Length;
				if (len > 0)
				{
					StatusBox.Select(len - 1, 1);
				}
				StatusBox.SelectedText += Text;
				StatusBox.ScrollToCaret();
				StatusBox.Update();
			}
		}
		//---------------------------------------------------------------------------------------------
		DateTime StartTime;
		DateTime lastCall;
		delegate void AddPosToProtokollCallback(int Progress, bool Final);
		public void AddPosToProtokoll(int Progress, bool Final)
		{
			if (this.StatusBox.InvokeRequired)
			{
				AddPosToProtokollCallback d = new AddPosToProtokollCallback(AddPosToProtokoll);
				this.Invoke(d, new object[] { Progress, Final});
			}
			else
			{
				if (Progress == -1)   // Init
				{
					StartTime = DateTime.Now;
				}
				else
				{

					if (Final == false)
					{
						TimeSpan deltaLastCall = DateTime.Now - lastCall;
						if (deltaLastCall.TotalMilliseconds <= 200)
							return;
					}




					int len = StatusBox.Text.Length;
					int pos = len - 1;
					while (StatusBox.Text[pos] != '\n')
						pos--;
					pos++;
					StatusBox.Select(pos, len - pos);   // letzte Zeile markieren

					TimeSpan x = DateTime.Now - StartTime;
					double millisec = x.TotalMilliseconds;

					if (millisec > 0)
					{
						string DL;
						string Time;
						string Speed;
						if (Progress <= 8000)
							DL = Progress.ToString() + " Byte";
						else if (Progress <= 8000000)
							DL = (Progress / 1024).ToString() + " kByte";
						else
							DL = (Progress / 1024 / 1024).ToString() + " MByte";

						Time = Math.Round(x.TotalSeconds) + " sec";


						double dlspeed = Progress / millisec;
						dlspeed = Math.Round(dlspeed, 1);
						Speed = dlspeed.ToString();

						StatusBox.SelectedText = "DL:" + DL + "\t DL Time:" + Time + "\t KByte/sec:" + Speed;

						lastCall = DateTime.Now;

						if (Final)
							AddTextToStatusBox("\r\n");
					}
				}
				StatusBox.ScrollToCaret();
				StatusBox.Update();
			}
		}

		//---------------------------------------------------------------------------------------------
		delegate void UpdateListStatusCallback(ListViewItem x, string StatusDownload);
		public void UpdateListStatus(ListViewItem x, string StatusDownload)
		{
			if (this.listView1.InvokeRequired)
			{
				UpdateListStatusCallback d = new UpdateListStatusCallback(UpdateListStatus);
				this.Invoke(d, new object[] { x, StatusDownload });
			}
			else
			{
				x.SubItems[0].Text = StatusDownload;
				if (StatusDownload.StartsWith("ok"))
                {
 					x.ForeColor = System.Drawing.Color.Black;
					x.BackColor = System.Drawing.Color.LightGreen;
                }
				else
                {
 					x.ForeColor = System.Drawing.Color.Black;
					x.BackColor = System.Drawing.Color.PeachPuff;
                }
			}
		}

		//---------------------------------------------------------------------------------------------
		delegate void UpdateProgressBarCallback(int Wert);
		public void UpdateProgressBar(int Wert)
		{
			if (this.progressBar1.InvokeRequired)
			{
				UpdateProgressBarCallback d = new UpdateProgressBarCallback(UpdateProgressBar);
				this.Invoke(d, new object[] { Wert });
			}
			else
			{
				progressBar1.Value = Wert;
			}
		}


		//---------------------------------------------------------------------------------------------
		static public string GetChecksum(string LocalFile)
		{
			if (File.Exists(LocalFile) == false)
			{
				return ("-no file-");
			}
			string erg = "";
			// Read File and generate an MD5 checksum
			byte[] FileData = File.ReadAllBytes(LocalFile);

			erg = FileData.Length.ToString() + ",";


			MD5 md5 = new MD5CryptoServiceProvider();
			byte[] result = md5.ComputeHash(FileData);
			foreach (byte x in result)
			{
				string Zeichen = x.ToString("X");
				while (Zeichen.Length < 2) Zeichen = "0" + Zeichen;
				erg += Zeichen;

			}
			return erg;
		}
		//---------------------------------------------------------------------------------------------
		string CheckFile(string LocalFile, string CheckSum)
		{
			if (File.Exists(LocalFile) == false)
			{
				//return ("nok (missing)");
				return ("    (missing)");
			}
			string CheckSumLocal = GetChecksum(LocalFile);
			if (CheckSumLocal != CheckSum)
			{
				//return ("nok (wrong MD5)");
				return ("    (wrong MD5)");
			}
			else
				return ("ok");
		}

		//---------------------------------------------------------------------------------------------
		public void DownloadFile(string downloadUrl, string fileName, ref string erg)
		{
			erg = "ok";
			Stream responseStream = null;
			FileStream fileStream = null;
			StreamReader reader = null;
			try
			{

				// a '@' inside of the login Name makes problems
				//  so I support a second format:    URL|LoginName|Password    The separator sign is the '|'


				WebRequest downloadRequest;
				if (downloadUrl.Contains("|") == true)
				{
					string[] Data = downloadUrl.Split(new Char[] { '|' });

					if (Data.Length != 3)
					{
						string Error = "Error: Wrong Custom URL Format! Please Use <URL>|<Login>|<Password> (Full URL:"+downloadUrl+")";
						throw (new Exception (Error));
					}
					string Url = Data[0];
					string Login = Data[1];
					string Password = Data[2];

					string msg = Url + " (login:" + Login + ", Password:" + Password + ")";

					AddTextToStatusBox("Start download of " + msg + "  to local file " + fileName + "\r\n");

					downloadRequest = WebRequest.Create(Url);
					downloadRequest.Credentials = new NetworkCredential(Login, Password);
				}
				else
				{
					AddTextToStatusBox("Start download of " + downloadUrl + " to local file " + fileName + "\r\n");
					downloadRequest = WebRequest.Create(downloadUrl);
				}


				WebResponse downloadResponse = downloadRequest.GetResponse();
				responseStream = downloadResponse.GetResponseStream();


				string xx=Directory.GetParent(fileName).ToString();
				Directory.CreateDirectory(xx);


				int Progress=0;
				fileStream = File.Create(fileName);
				byte[] buffer = new byte[10240];
				int bytesRead;
				AddPosToProtokoll(-1,false);
				while (true)
				{
					bytesRead = responseStream.Read(buffer, 0, buffer.Length);
					if (bytesRead == 0)
						break;
					fileStream.Write(buffer, 0, bytesRead);

					Progress+=bytesRead;

					//AddTextToStatusBox(".");
					AddPosToProtokoll(Progress, false);

				}
				AddPosToProtokoll(Progress, true);
				AddTextToStatusBox("Download complete.\r\n");
			}
			catch (UriFormatException ex)
			{
				AddTextToStatusBox("Error:\r\n");
				AddTextToStatusBox(ex.Message + "\r\n");
				erg = "nok (" + ex.Message + ")";
			}
			catch (WebException ex)
			{
				AddTextToStatusBox("Error:\r\n");
				AddTextToStatusBox(ex.Message + "\r\n");
				erg = "nok (" + ex.Message + ")";
			}
			catch (IOException ex)
			{
				AddTextToStatusBox("Error:\r\n");
				AddTextToStatusBox(ex.Message + "\r\n");
				erg = "nok (" + ex.Message + ")";
			}
			catch (Exception ex)
			{
				AddTextToStatusBox("Error:\r\n");
				AddTextToStatusBox(ex.Message + "\r\n");
				erg = "nok (" + ex.Message + ")";
			}

			finally
			{
				if (reader != null)
					reader.Close();
				else if (responseStream != null)
					responseStream.Close();
				if (fileStream != null)
					fileStream.Close();
			}
		}
		//---------------------------------------------------------------------------------------------
		public void DecompressFile(string seven_zFile, string LocalFile, ref string StatusDecompres)
		{
			try
			{
				AddTextToStatusBox("Start decompress of File " + seven_zFile+"\r\n");
				//                string Aufrufparameter = "d " + seven_zFile+" "+ LocalFile;
				//                SevenZip.LzmaAlone.Main2(Aufrufparameter.Split());

				string[] Aufrufparameter = new string[3];
				Aufrufparameter[0] = "d";
				Aufrufparameter[1] = seven_zFile;
				Aufrufparameter[2] = LocalFile;
				SevenZip.LzmaAlone.Main2(Aufrufparameter);

				AddTextToStatusBox("Decompress complete.\r\n");
				StatusDecompres = "ok";
			}
			catch (Exception ex)
			{
				AddTextToStatusBox("Error:"+ex.Message+"\r\n");
				StatusDecompres = "nok (Decompress:" + ex.Message+")";
			}

		}
		//---------------------------------------------------------------------------------------------
		string CheckFile(string nwfolder, string worldFolder, string ext)
		{
			string status = "";
			if (nwfolder == "hak")
			{
				if (ext == "hak");
			}
			else if (nwfolder == "modules")
			{
				
			}
			return status;
		}
		
		//---------------------------------------------------------------------------------------------
		void installWorldFolder(string dirName)
		{
			string WorldFolder = GetStringFromKey(KeyIndex.Folder);
			
			string lyndata = ".lynsync.dat";
			FileInfo lynsyncFile = new FileInfo(dirName + "\\" + lyndata);
			if (lynsyncFile.Exists)
			{
				StreamReader lynDat = lynsyncFile.OpenText();
				string isoFolder = lynDat.ReadLine();
				lynDat.Close();

				AddTextToStatusBox("===============iso hak:  " + isoFolder + "\r\n");
				if (isoFolder != WorldFolder)
				{
					CleanOutFolder(dirName, isoFolder);
					RestoreFolder(dirName, WorldFolder);
				}
			}
			else
			{
				CleanOutFolder(dirName);
				RestoreFolder(dirName, WorldFolder);
			}
			FileInfo newLynsyncFile = new FileInfo(dirName + "\\" + lyndata);			
			if (!newLynsyncFile.Exists)
			{
				StreamWriter lynDat = newLynsyncFile.CreateText();
				lynDat.WriteLine(WorldFolder);
				lynDat.Close();
			}
		}
		//---------------------------------------------------------------------------------------------
		void uninstallWorldFolder(string dirName)
		{
			string lyndata = ".lynsync.dat";
			FileInfo lynsyncFile = new FileInfo(dirName + "\\" + lyndata);
			if (lynsyncFile.Exists)
			{
				StreamReader lynDat = lynsyncFile.OpenText();
				string isoFolder = lynDat.ReadLine();
				lynDat.Close();

				CleanOutFolder(dirName, isoFolder);
				RestoreFolder(dirName);
			}
		}
		//---------------------------------------------------------------------------------------------
		void deleteWorldFolder(string dirName, string worldFolder)
		{
			string lyndata = ".lynsync.dat";
			FileInfo lynsyncFile = new FileInfo(dirName + "\\" + lyndata);
			if (lynsyncFile.Exists)
			{
				StreamReader lynDat = lynsyncFile.OpenText();
				string isoFolder = lynDat.ReadLine();
				lynDat.Close();

				if (isoFolder == worldFolder)
				{
					CleanOutFolder(dirName, isoFolder);
					RestoreFolder(dirName);
				}
			}
			
			string baseStorePath = setupWorldStorePath();
			DirectoryInfo dir = new DirectoryInfo(dirName);
			DirectoryInfo dirStore = new DirectoryInfo(baseStorePath + "\\" + worldFolder);
			if (!dirStore.Exists) dirStore.Create();

			string dirStoreFolder = dir.Name;
			if (dir.Parent.Name.ToLower() == "ui") 
			{
				dirStoreFolder = "ui\\"+dirStoreFolder;
				DirectoryInfo uiStore = new DirectoryInfo(dirStore.FullName + "\\ui");
				if (!uiStore.Exists) uiStore.Create();
			}
			DirectoryInfo removeDir = new DirectoryInfo(dirStore.FullName + "\\" + dirStoreFolder);
			if (removeDir.Exists)
			{
				removeDir.Delete(true);
				AddTextToStatusBox("    Removed " + removeDir.FullName + "\r\n");
			}
		}
		
		//---------------------------------------------------------------------------------------------
		void CleanOutFolder(string dirName)
		{
			CleanOutFolder(dirName, "LynsyncDefault");
		}
		//---------------------------------------------------------------------------------------------
		string setupWorldStorePath()
		{
			FileInfo appPath = new FileInfo(Application.ExecutablePath);
			string baseStorePath = appPath.DirectoryName + "\\worlds";
			DirectoryInfo baseStore = new DirectoryInfo(baseStorePath);
			if (!baseStore.Exists) baseStore.Create();
			
			return baseStorePath;
		}
		//---------------------------------------------------------------------------------------------
		void CleanOutFolder(string dirName, string folderName)
		{
			string baseStorePath = setupWorldStorePath(); 
			DirectoryInfo dir = new DirectoryInfo(dirName);
			//DirectoryInfo dirStore = new DirectoryInfo(dirName + "\\" + folderName);
			DirectoryInfo dirStore = new DirectoryInfo(baseStorePath + "\\" + folderName);
			if (!dirStore.Exists) dirStore.Create();

			string dirStoreFolder = dir.Name;
			if (dir.Parent.Name.ToLower() == "ui") 
			{
				dirStoreFolder = "ui\\"+dirStoreFolder;
				DirectoryInfo uiStore = new DirectoryInfo(dirStore.FullName + "\\ui");
				if (!uiStore.Exists) uiStore.Create();
			}
		    AddTextToStatusBox("===============CleanOutFolder:  to: " + dirStore.FullName + "\\" + dirStoreFolder + "\r\n");
			dir.MoveTo(dirStore.FullName + "\\" + dirStoreFolder);
			DirectoryInfo emptyDir = new DirectoryInfo(dirName);
			emptyDir.Create();
//			FileInfo[] cleanFiles = dir.GetFiles();
//			foreach (FileInfo cfile in cleanFiles)
//			{
//				cfile.MoveTo(dirStore.FullName + "\\" + cfile.Name);
//			}		
		}
		//---------------------------------------------------------------------------------------------
		void RestoreFolder(string dirName)
		{
			RestoreFolder(dirName, "LynsyncDefault");
		}
		//---------------------------------------------------------------------------------------------
		void RestoreFolder(string dirName, string folderName)
		{
			string baseStorePath = setupWorldStorePath(); 
			DirectoryInfo baseStore = new DirectoryInfo(baseStorePath);
			if (!baseStore.Exists) return;
			DirectoryInfo dir = new DirectoryInfo(dirName);
			if (!dir.Exists) return;
			//DirectoryInfo dirStore = new DirectoryInfo(dirName + "\\" + folderName);
			string dirStoreFolder = dir.Name;
			if (dir.Parent.Name.ToLower() == "ui") dirStoreFolder = "ui\\"+dirStoreFolder;
			DirectoryInfo dirStore = new DirectoryInfo(baseStorePath + "\\" + folderName + "\\" + dirStoreFolder);
			if (!dirStore.Exists) return;
		    AddTextToStatusBox("===============RestoreFolder:  from: " + dirStore.FullName + "\r\n");
			
			// Update: Add check to see that this is empty
			dir.Delete();
			dirStore.MoveTo(dir.FullName);
//			FileInfo[] restoreFiles = dirStore.GetFiles();
//			foreach (FileInfo rfile in restoreFiles)
//			{
//				rfile.MoveTo(dir.FullName + "\\" + rfile.Name);
//			}		
			
		}
		//---------------------------------------------------------------------------------------------
		void MoveIsolatedFiles()
		{			
			string path = LocalFilePath + "\\" + "hak";
			bool isIsolated = GetOptionFromKey("iso_hak");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);

			path = LocalFilePath + "\\" + "override";
			isIsolated = GetOptionFromKey("iso_override");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);
			
			path = LocalFilePath + "\\" + "portraits";
			isIsolated = GetOptionFromKey("iso_portraits");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);
			
			path = LocalFilePath + "\\" + "tlk";
			isIsolated = GetOptionFromKey("iso_tlk");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);
			
			path = LocalFilePath + "\\" + "ui\\custom";
			isIsolated = GetOptionFromKey("iso_uiCustom");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);
			
			path = LocalFilePath + "\\" + "ui\\default";
			isIsolated = GetOptionFromKey("iso_uiDefault");
			if (isIsolated) installWorldFolder(path);
			else RestoreFolder(path);			
		}
		//---------------------------------------------------------------------------------------------
		void RestoreDefaultFiles()
		{
			
		}
		//---------------------------------------------------------------------------------------------
		string ValidNwFolderAndExt(string NwFolderName,string WorldFolder, string ExtName)
		{
			string status = "";
			string nwfolder = NwFolderName.ToLower();
			string ext = ExtName.ToLower();
			bool confirmExt = GetOptionFromKey("confirmExt");
			bool confirmFolder = GetOptionFromKey("confirmFolder");
			string setWorldfolder = GetStringFromKey(KeyIndex.Folder).ToLower();
			string givenWorldFolder = WorldFolder.ToLower();
			switch (nwfolder)
			{
				case "modules":
					if (setWorldfolder != givenWorldFolder) status = "wrong folder";
					else if ( confirmExt &&
					   ext != ".trx" && 
					   ext != ".sef" && 
					   ext != ".jrl" && 
					   ext != ".pfx" 
					  ) status = "bad ext";
					break;
				case "campaigns":
					if (setWorldfolder != givenWorldFolder) status = "wrong folder";
					else if ( confirmExt &&
					         ext != ".tga" &&
					         ext != ".cam" &&
					         ext != ".wmp" &&
					         ext != ".xml" &&
					         ext != ".jrl"
					        ) status = "bad ext";
					break;
				case "hak":
					if ( confirmExt && ext != ".hak"
					        ) status = "bad ext";
					break;
//				case "pwc":
//					if ( confirmExt && ext != ".pwc"
//					        ) status = "bad ext";
//					break;
				case "tlk":
					if ( confirmExt && ext != ".tlk"
					        ) status = "bad ext";
					break;
				case "override":
					if ( confirmExt &&
					    ext != ".tga" &&
					    ext != ".2da"
					        ) status = "bad ext";
					break;
				case "ui\\custom":
					if ( confirmExt &&
					    ext != ".tga" &&
					    ext != ".ini" &&
					    ext != ".xml"
					        ) status = "bad ext";
					break;
				case "ui\\default":
					if ( confirmExt &&
					    ext != ".tga" &&
					    ext != ".ini" &&
					    ext != ".xml"
					        ) status = "bad ext";
					break;
				case "portraits":
					if ( confirmExt && ext != ".tga"
					        ) status = "bad ext";
					break;
				default:
					if (confirmFolder) status = "unrecognized nwfolder";
					break;
			}
			return status;
		}
		//---------------------------------------------------------------------------------------------
		void CheckLocalFiles()
		{
			listView1.Items.Clear();    // remove old Data;

			String Zeile;
			try
			{
				MoveIsolatedFiles();
				
				StreamReader E1 = File.OpenText(Download_File_List);
				UpdateProgressBar(0);

				// Datei lesen
				List<string> List = new List<string>();
				while ((Zeile = E1.ReadLine()) != null)
				{
					List.Add(Zeile);
				}
				E1.Close();


				int Counter = 0;
				foreach (string curZeile in List)
				{
					UpdateProgressBar((100 * Counter) / List.Count);
					Zeile = curZeile.Trim();
					if (Zeile.Length > 0)
					{
						if (Zeile[0] != '#')
						{
							string[] Data = Zeile.Split('\t');
							if (Data.Length >= 3)
							{
								string SourceFile = Data[0];
                                string LocalBase = Data[1];
                                string LocalFile = LocalFilePath + "\\" + LocalBase;
								string CheckSum = Data[2];
								int folderNameLength = Data[1].IndexOf('\\');
								
                                //AddTextToStatusBox("Check Data1:" + Data[1] + " ");
								FileInfo file = new FileInfo("Parent\\"+Data[1]);
								DirectoryInfo dir = file.Directory;
								string ExtName = file.Extension;
								string BaseName = file.Name;
								string NwFolderName = dir.Name;
								string WorldFolderName = "";
								int ix = BaseName.LastIndexOf(ExtName);
								ix = (ix>0) ? ix : BaseName.Length;
								BaseName = BaseName.Substring(0,ix);
								string firstDir = "";
								
								while (dir.Parent.Name != "Parent")
								{
									dir = dir.Parent;
									firstDir = WorldFolderName;
									WorldFolderName = NwFolderName;
									NwFolderName = dir.Name;
								}
								if (NwFolderName.ToLower() == "ui")
								{
									NwFolderName = NwFolderName + "\\" + WorldFolderName;
									WorldFolderName = "";
								}
								else if (firstDir != "") BaseName = firstDir + "\\" + BaseName;

								AddTextToStatusBox("Check local File:" + LocalFile + " ");
								string Status = CheckFile(LocalFile, CheckSum);
								string Security = ValidNwFolderAndExt(NwFolderName,WorldFolderName,ExtName);
								
								AddTextToStatusBox(Status + " " + Security + "\r\n");
								
								ListViewItem x = new ListViewItem(Status);
								x.SubItems.Add(NwFolderName.ToLower());
								x.SubItems.Add(WorldFolderName);
								x.SubItems.Add(BaseName);
								x.SubItems.Add(ExtName.ToLower());
								x.SubItems.Add(LocalFile);
								x.SubItems.Add(SourceFile);
								x.SubItems.Add(CheckSum);
								
								if (Status.StartsWith("ok") == false)
								{
									x.ForeColor = System.Drawing.Color.Black;
									x.BackColor = System.Drawing.Color.Yellow;
								}
								if (Security != "")
								{
									x.BackColor = System.Drawing.Color.Red;
								}
								
								listView1.Items.Add(x);
								listView1.Update();
							}
							else
							{
								AddTextToStatusBox(" Error: Wrong syntax in " + Download_File_List + " file. This line will be ignored:'" + Zeile + "'\r\n");
							}
						}
					}
					Counter++;
				}
				UpdateProgressBar(100);
			}
			catch(Exception ex)
			{
				AddTextToStatusBox("Error:\r\n");
				AddTextToStatusBox(ex.Message + "\r\n");
			}
			finally
			{
				
			}

		}
		//---------------------------------------------------------------------------------------------
		private void UpdateGroups_List()
		{
			comboBoxGroup.Items.Clear();
			AddTextToStatusBox("Reading "+GROUPS_INI_File+"\r\n");
			try
			{
				bool FirstLine = true;
				StreamReader E1 = File.OpenText(GROUPS_INI_File);
				{
					string Zeile;
					while ((Zeile = E1.ReadLine()) != null)
					{
						Zeile = Zeile.Trim();
						if (Zeile.Length > 0)
						{
							comboBoxGroup.Items.Add(Zeile);
							if (FirstLine)
							{
								comboBoxGroup.Text = Zeile;
								FirstLine = false;
							}
						}
					}
					E1.Close();
				}
			}
			catch //(Exception ex)
			{

			}
		}
		//---------------------------------------------------------------------------------------------
		private void UpdatePW_List()
		{
			comboBoxWorld.Enabled = true;
			comboBoxWorld.Items.Clear();
			WorldLines.Clear();
			AddTextToStatusBox("Reading "+INI_File+"\r\n");
			try
			{
				bool FirstLine = true;
				
				StreamReader E1 = File.OpenText(INI_File);
				{
					string worldLine;
					string worldName;
					while ((worldLine = E1.ReadLine()) != null)
					{
						worldLine = worldLine.Trim();
						worldName = (Regex.Split(worldLine," -- "))[0] + " [[" + (Regex.Split(worldLine," -- "))[1] + "]]";

						if (worldName.Length > 0)
						{
							WorldLines.Add(worldLine);
							comboBoxWorld.Items.Add(worldName);
							if (FirstLine)
							{
								comboBoxWorld.Text = worldName;
								FirstLine = false;
							}
						}
					}
					E1.Close();
				}
			}
			catch //(Exception ex)
			{

			}
		}
		//---------------------------------------------------------------------------------------------
		public void SaveKey(string key)
		{
			int index = comboBoxWorld.SelectedIndex;
			WorldLines[index] = key;
			StreamWriter A3 = File.CreateText(INI_File);
			foreach (string line in WorldLines) A3.WriteLine(line);
			A3.Close();
			
			UpdatePW_List();
			
			comboBoxWorld.SelectedIndex = index;
		}
		//---------------------------------------------------------------------------------------------
		public void AddNewKey(string key)
		{
			int index = WorldLines.Add(key);
			
			// Add try block
			StreamWriter A3 = File.CreateText(INI_File);
			foreach (string line in WorldLines) A3.WriteLine(line);
			A3.Close();
			
			UpdatePW_List();
			
			comboBoxWorld.SelectedIndex = index;
		}
		//---------------------------------------------------------------------------------------------
		public string GetStringFromKey(KeyIndex index)
		{
			int i = (int)index;
			string key = (string)WorldLines[comboBoxWorld.SelectedIndex];
			string[] splitLine = Regex.Split(key," -- ");
			int length = splitLine.Length;
			if (length>i) return splitLine[i];
			else return "";
		}
		//---------------------------------------------------------------------------------------------
		public bool GetOptionFromKey(string name)
		{
			string options = GetStringFromKey(KeyIndex.Options);
			return options.Contains(name);
		}
		//---------------------------------------------------------------------------------------------
		public string TestRemoteIni(string downloadUrl)
		{
			if (downloadUrl.Contains(" "))
			{
				downloadUrl= downloadUrl.Substring(0,downloadUrl.IndexOf(' '));
			}

			string FileName = Download_File_List;
			string statusDownload = "?";
			DownloadFile(downloadUrl, FileName, ref statusDownload);
			return statusDownload;
		}
		//---------------------------------------------------------------------------------------------
        public string EnterWorld(string world, string application, string server, string password, bool isPopup, bool isCopybuf, bool isPassLogin)
		{
			AddTextToStatusBox("Enter server:: " + server+"\r\n");
			AddTextToStatusBox("Enter passwd:: " + password+"\r\n");
			if (isCopybuf)
			{
				Clipboard.SetDataObject(server);
				AddTextToStatusBox("Added server:: " + server+" to clipboard\r\n");
			}
			if (isPopup)
			{
				LoginInfo x = new LoginInfo(world, server, password);
				x.Show();
				//x.ShowDialog();
				//MessageBox.Show(server + "\n" + password,"World login",MessageBoxButtons.OK,MessageBoxIcon.Information);
			}

			if (application == "") return "ok";
			
        	string arguments = "";
        	if (isPassLogin)
        	{
        		arguments = "+connect " + server;
        	    if (password != "") arguments += "+password" + password;
        	}
			string game = "";
			try
			{
				game = GameExe + " " + application;
				ProcessStartInfo startInfo = new ProcessStartInfo(GameExe);
				startInfo.WindowStyle = ProcessWindowStyle.Minimized;
				
				//Process.Start(startInfo);
				startInfo.WorkingDirectory = GameExePath;
				startInfo.Arguments = arguments;
				startInfo.UseShellExecute = false;
				//startInfo.CreateNoWindow = true;

				Process.Start(startInfo);
				//System.Diagnostics.Process.Start(GameExe, splitLine[4]);
				
				return "ok";
			}
			catch
			{
				MessageBox.Show("Sorry, I can't enter world:" + game + "\n","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
				return "not ok";
			}
		}
		
		//---------------------------------------------------------------------------------------------
		public MainWindow()
		{
			InitializeComponent();
			comboBoxWorld.Text = "Enter your Ini-File Address here.";
			UpdateGroups_List();
			//UpdatePW_List();
		}
		//---------------------------------------------------------------------------------------------
		private void CheckButton1_Click(object sender, EventArgs e)
		{
        	SetPaths(GetOptionFromKey("nwn2"), 
        	        GetOptionFromKey("useMyDocs")
        	        );
			if (CheckThread() == true)
				return;

			UpdateProgressBar(0);
			progressBar1.ForeColor = Color.Yellow;


			string FileName = Download_File_List;
			
			// download File
			// "file:///C:/nwn2_DownloadManager.ini";

			listView1.Items.Clear();
			
			string currentLine = (string)WorldLines[comboBoxWorld.SelectedIndex];
			string  downloadUrl = (Regex.Split(currentLine," -- "))[3];

			if (downloadUrl.Length == 0)
			{
				AddTextToStatusBox("Error:  No Address.  Please select one from the combo box.\r\n");
				return;
			}


			// You can place some descriptions behind the URL.
			// The separator is the first Space charater.   ( Space is not part of a vaild URL )
			if (downloadUrl.Contains(" "))
			{
				downloadUrl= downloadUrl.Substring(0,downloadUrl.IndexOf(' '));
			}


			string StatusDownload = "?";
			DownloadFile(downloadUrl, FileName, ref StatusDownload);
			if (StatusDownload == "ok")
			{
				// Check Local Files
				CheckLocalFiles();
			}
		}
        //---------------------------------------------------------------------------------------------
        private void Download2_Thread_Test()
        {
            int Downloads = 0;
            // Start with downlaod

            int Counter = 0;
            foreach (ListViewItem x in List_4_Download2)
            {
//                 x.EnsureVisible();

                UpdateProgressBar(100*Counter / List_4_Download2.Count);
                Counter++;

                string Status = x.Text;
                string LocalFile = x.SubItems[5].Text;
                string RemoteFile = x.SubItems[6].Text;
                string seven_zFile = LocalFile + ".compressed(7z)";
                bool Decompress7z = false;

                if ((RemoteFile.Contains(".7z") == true || RemoteFile.Contains(".7Z") == true)
                && (LocalFile.Contains(".7z") == false && LocalFile.Contains(".7Z") == false))
                    Decompress7z = true;

                if (Status.StartsWith("ok") == false &&
                    Status.StartsWith("(confirm") == false)
                {

                    Downloads++;
                    string StatusDownload = "?";
                    AddTextToStatusBox( LocalFile + "\r\n");
                    if (Decompress7z == false)
                    {
                        DownloadFile(RemoteFile, LocalFile, ref StatusDownload);
                        UpdateListStatus(x, StatusDownload);
                    }
                    else
                    {
                        DownloadFile(RemoteFile, seven_zFile, ref StatusDownload);
                        UpdateListStatus(x, StatusDownload);

                        if (StatusDownload == "ok")
                        {
                            string StatusDecompres = "?";
                            DecompressFile(seven_zFile, LocalFile, ref StatusDecompres);
                            UpdateListStatus(x, StatusDecompres);
                            if (StatusDecompres == "ok")
                            {
                                try
                                {
                                    AddTextToStatusBox("Delete file " + seven_zFile + "\r\n");
                                    File.Delete(seven_zFile);
                                }
                                catch (Exception ex)
                                {
                                    AddTextToStatusBox("Cant delete file:" + ex.Message + "\r\n");
                                }
                            }
                        }
                    }
                }

//                listView1.Update();
//                this.Refresh();


            }
            UpdateProgressBar(100);
            if (Downloads == 0)
                AddTextToStatusBox("All files are ok, you don't need to download anything.\r\n");
            else
                AddTextToStatusBox("Download done. (Changed Files:" + Downloads.ToString() + ")\r\n");

            ThreadRuningFlag = false;
        }

		//---------------------------------------------------------------------------------------------
		private void Download2_Thread()
		{
			int Downloads = 0;
			// Start with downlaod

			int Counter = 0;
			foreach (ListViewItem x in List_4_Download2)
			{
				//                 x.EnsureVisible();

				UpdateProgressBar(100*Counter / List_4_Download2.Count);
				Counter++;

                string Status = x.Text;
                string LocalFile = x.SubItems[5].Text;
                string RemoteFile = x.SubItems[6].Text;
				string seven_zFile = LocalFile + ".compressed(7z)";
				bool Decompress7z = false;

				if ((RemoteFile.Contains(".7z") == true || RemoteFile.Contains(".7Z") == true)
				    && (LocalFile.Contains(".7z") == false && LocalFile.Contains(".7Z") == false))
					Decompress7z = true;

				if (Status.StartsWith("ok") == false &&
				    x.BackColor != System.Drawing.Color.Red )
				{

					Downloads++;
					string StatusDownload = "?";
					if (Decompress7z == false)
					{
						DownloadFile(RemoteFile, LocalFile, ref StatusDownload);
						UpdateListStatus(x, StatusDownload);
					}
					else
					{
						DownloadFile(RemoteFile, seven_zFile, ref StatusDownload);
						UpdateListStatus(x, StatusDownload);

						if (StatusDownload == "ok")
						{
							string StatusDecompres = "?";
							DecompressFile(seven_zFile, LocalFile, ref StatusDecompres);
							UpdateListStatus(x, StatusDecompres);
							if (StatusDecompres == "ok")
							{
								try
								{
									AddTextToStatusBox("Delete file " + seven_zFile + "\r\n");
									File.Delete(seven_zFile);
								}
								catch (Exception ex)
								{
									AddTextToStatusBox("Cant delete file:" + ex.Message + "\r\n");
								}
							}
						}
					}
				}

				//                listView1.Update();
				//                this.Refresh();


			}
			UpdateProgressBar(100);
			if (Downloads == 0)
				AddTextToStatusBox("All files are ok, you don't need to download anything.\r\n");
			else
				AddTextToStatusBox("Download done. (Changed Files:" + Downloads.ToString() + ")\r\n");

			ThreadRuningFlag = false;
		}
		//---------------------------------------------------------------------------------------------

		List<ListViewItem> List_4_Download2;
		//---------------------------------------------------------------------------------------------
		private void UpdateButton2_Click(object sender, EventArgs e)
		{
        	SetPaths(GetOptionFromKey("nwn2"), 
        	        GetOptionFromKey("useMyDocs")
        	        );
			if (CheckThread() == true)
				return;


			UpdateProgressBar(0);
			progressBar1.ForeColor = Color.Lime;


			ThreadRuningFlag = true;
			if (listView1.Items.Count == 0)
			{
				AddTextToStatusBox("Error: There are no Data. Please download a Ini File first.\r\n");
				return;
			}

			if (List_4_Download2 == null)
				List_4_Download2 = new List<ListViewItem>();
			else
				List_4_Download2.Clear();

			foreach (ListViewItem x in listView1.Items)
			{
				List_4_Download2.Add(x);
			}
			
            System.Threading.Thread t = new System.Threading.Thread((Download2_Thread_Test));
			t.Start();
		}
		//---------------------------------------------------------------------------------------------
		private void GroupTextChanged(object sender, EventArgs e)
		{
			INI_File = "groups\\" + comboBoxGroup.Text + ".ini";
			if (GameExePath.StartsWith("****"))
			{
				comboBoxWorld.Items.Clear();
				comboBoxWorld.Enabled = false;
				AddTextToStatusBox(GameExePath+"\r\n");
			}
			else
			{
				UpdatePW_List();
			}
		}
		
		//---------------------------------------------------------------------------------------------
		private void EnterButton3_Click(object sender, EventArgs e)
		{
        	SetPaths(GetOptionFromKey("nwn2"), 
        	        GetOptionFromKey("useMyDocs")
        	        );
			EnterWorld(GetStringFromKey(KeyIndex.Name),
			           GetStringFromKey(KeyIndex.App),
			           GetStringFromKey(KeyIndex.Server),
			           GetStringFromKey(KeyIndex.Password),
			           GetOptionFromKey("popup"),
        	           GetOptionFromKey("copyBuf"), 
        	           GetOptionFromKey("passLogin") 
			          );
		}
		//---------------------------------------------------------------------------------------------
		private void BrowseButton_Click(object sender, EventArgs e)
		{
			string website = "";
			try
			{
				string currentLine = (string)WorldLines[comboBoxWorld.SelectedIndex];
				string[] splitLine = Regex.Split(currentLine," -- ");
				website = "http://" + splitLine[2];
				AddTextToStatusBox("Browse "+website+"\r\n");
				System.Diagnostics.Process.Start(website);
			}
			catch
			{
				MessageBox.Show("Sorry, I can't browse the site:" + website + "\n","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
			}
		}
		//---------------------------------------------------------------------------------------------
		private void WorldOptionsButton_Click(object sender, EventArgs e)
		{
			WorldOptionsPage x = new WorldOptionsPage(this);
			x.ShowDialog();
		}
		
		//---------------------------------------------------------------------------------------------
		private void AddButton_Click(object sender, EventArgs e)
		{
			if (comboBoxWorld.Items.Contains(comboBoxWorld.Text) == true)
			{
				AddTextToStatusBox("The Address "+comboBoxWorld.Text +" is already in your List\r\n");
			}
			else
			{
				comboBoxWorld.Items.Add(comboBoxWorld.Text);
				StreamWriter A3 = File.CreateText(INI_File);
				foreach (string text in comboBoxWorld.Items)
					A3.WriteLine(text);
				A3.Close();
			}
		}
		
		//---------------------------------------------------------------------------------------------
		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Close();
		}
		//---------------------------------------------------------------------------------------------
		private void exploreGroupsStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				System.Diagnostics.Process.Start("explorer.exe", "groups");

			}
			catch
			{
				MessageBox.Show("Sorry, I can't explore the groups folder\n","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
			}
			
		}

		//---------------------------------------------------------------------------------------------
		private void EditGroupsButton_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(GROUPS_INI_File);
		}
		//---------------------------------------------------------------------------------------------
		private void UpdateGroupsButton_Click(object sender, EventArgs e)
		{
			UpdateGroups_List();
		}
		//---------------------------------------------------------------------------------------------
		private void EditWorldsButton_Click(object sender, EventArgs e)
		{
			try
			{
				if ( File.Exists(INI_File) == false ) File.Create(INI_File).Close();
			
				System.Diagnostics.Process.Start(INI_File);
			}
			catch
			{
				MessageBox.Show("Sorry, I can't edit world list\n","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
			}			
		}
		//---------------------------------------------------------------------------------------------
		private void UpdateWorldsButton_Click(object sender, EventArgs e)
		{
			UpdatePW_List();
		}

		//---------------------------------------------------------------------------------------------
		private void RestoreButton_Click(object sender, EventArgs e)
		{	
			//must restore all paths
			uninstallWorldFolder(LocalFilePath + "\\" + "hak");
			uninstallWorldFolder(LocalFilePath + "\\" + "override");
			uninstallWorldFolder(LocalFilePath + "\\" + "portraits");
			uninstallWorldFolder(LocalFilePath + "\\" + "tlk");
			uninstallWorldFolder(LocalFilePath + "\\" + "ui\\custom");
			uninstallWorldFolder(LocalFilePath + "\\" + "ui\\default");
			listView1.Items.Clear();
		}
		//---------------------------------------------------------------------------------------------
		private void ExitButton_Click(object sender, EventArgs e)
		{
			if (CheckThread() == true)
				return;
			Close();
		}
		
		// Menu Click actions

			// File menu actions
		
			// Action menu actions
		
			// View menu actions
			
		//---------------------------------------------------------------------------------------------
		private void showOnlyFilesToolStripMenuItem_Click(object sender, EventArgs e)
		{
			splitContainer1.Panel1Collapsed = false;
			splitContainer1.Panel2Collapsed = true;
			this.showOnlyFilesToolStripMenuItem.Enabled = false;
			this.showOnlyStatusToolStripMenuItem.Enabled = true;
			this.showBothToolStripMenuItem.Enabled = true;
		}
		//---------------------------------------------------------------------------------------------
		private void showOnlyStatusToolStripMenuItem_Click(object sender, EventArgs e)
		{
			splitContainer1.Panel1Collapsed = true;
			splitContainer1.Panel2Collapsed = false;
			this.showOnlyFilesToolStripMenuItem.Enabled = true;
			this.showOnlyStatusToolStripMenuItem.Enabled = false;
			this.showBothToolStripMenuItem.Enabled = true;
		}
		//---------------------------------------------------------------------------------------------
		private void showBothToolStripMenuItem_Click(object sender, EventArgs e)
		{
			splitContainer1.Panel1Collapsed = false;
			splitContainer1.Panel2Collapsed = false;
			this.showOnlyFilesToolStripMenuItem.Enabled = true;
			this.showOnlyStatusToolStripMenuItem.Enabled = true;
			this.showBothToolStripMenuItem.Enabled = false;
		}
		//---------------------------------------------------------------------------------------------
		private void refreshToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.PerformLayout();
		}		
			
		    // Help menu actions
		    		    
		//---------------------------------------------------------------------------------------------
		private void instructionsPageToolStripMenuItem_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(@"http://code.google.com/p/lynsync/wiki/Player_Instructions");			
		}
		//---------------------------------------------------------------------------------------------
		private void faqToolStripMenuItem_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(@"http://code.google.com/p/lynsync/wiki/FAQ");
		}
		//---------------------------------------------------------------------------------------------
		private void reportIssueToolStripMenuItem_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(@"http://code.google.com/p/lynsync/issues/entry");
		}
		//---------------------------------------------------------------------------------------------
		private void lynsyncUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(@"http://code.google.com/p/lynsync/downloads/list");
		}
		//---------------------------------------------------------------------------------------------
		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			About x = new About(VersionText);
			x.ShowDialog();
		}
		
		//---------------------------------------------------------------------------------------------

	}
}
